package com.usian.service.impl;

import com.github.pagehelper.PageHelper;
import com.usian.mapper.SearchItemMapper;
import com.usian.pojo.SearchItem;
import com.usian.pojo.SearchItem2;
import com.usian.service.SearchItemService;
import com.usian.utils.JsonUtils;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.IndicesClient;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@Transactional
public class SearchItemServiceImpl implements SearchItemService {
    @Resource
    private SearchItemMapper searchItemMapper;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Value("${ES_INDEX_NAME}")
    private String ES_INDEX_NAME;

    @Value("${ES_TYPE_NAME}")
    private String ES_TYPE_NAME;
    @Override
    public boolean importAll() {

        try {
            if (!isExistsIndex()){
                createIndex();
            }
            int pages=1;
            while (true){
                //每页一千条
                PageHelper.startPage(pages,1000);
                //1、查询mysql中的商品信息
                List<SearchItem> itemList = searchItemMapper.getItemList();
                if (itemList.size()==0 || itemList==null){
                  break;
                }
                //批量添加
                //批量添加es对象
                BulkRequest bulkRequest = new BulkRequest();
                for (int i = 0; i < itemList.size(); i++) {
                    SearchItem searchItem = itemList.get(i);
                    //把商品信息添加到es中
                    bulkRequest.add(new IndexRequest(ES_INDEX_NAME, ES_TYPE_NAME).
                            source(JsonUtils.objectToJson(searchItem), XContentType.JSON));
                }
                restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
                //循环一下加一下
                pages++;
            }
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }

    }
//分页查询名字、类别、描述、卖点包含q的商品  商品搜索
    @Override
    public List<SearchItem2> selectByq(String q, Long page, Integer pageSize) {
        try {
        // 搜索请求对象索引名
        SearchRequest searchRequest = new SearchRequest(ES_INDEX_NAME);//索引代表mysql里的database
        //表明
        searchRequest.types(ES_TYPE_NAME);//type代表MySQL里的表
        //构建搜索条件对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //1、查询名字、描述、卖点、类别包括“q”的商品
        searchSourceBuilder.query(QueryBuilders.multiMatchQuery(q,new String[]{ "itemTitle","itemDesc","itemSellPoint","itemCategoryName"}));
        //2、分页 公式是page-1 * pageSize
        Long  from = (page - 1) * pageSize;
        searchSourceBuilder.from(from.intValue());
        searchSourceBuilder.size(pageSize);
        //3、高亮 创建高亮条件Builder
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        //高亮前缀
        highlightBuilder.preTags("<font color='red'>");
        //高亮后缀
        highlightBuilder.postTags("</font>");
        //匹配谁亮
        highlightBuilder.field("itemTitle");
        //把高亮条件传给搜索条件
        searchSourceBuilder.highlighter(highlightBuilder);
        //把搜索条件对象传给请求对象
        searchRequest.source(searchSourceBuilder);
        //请求响应
            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            //返回结果
            SearchHit[] hits = search.getHits().getHits();
            ArrayList<SearchItem> searchItemList = new ArrayList<>();
            ArrayList<SearchItem2> searchItemList2 = new ArrayList<>();

            for (int i=0; i<hits.length; i++) {
                //把查出的数据json转成Java
                SearchItem searchItem = JsonUtils.jsonToPojo(hits[i].getSourceAsString(), SearchItem.class);
                SearchItem2 searchItem2 = new SearchItem2(searchItem.getId(),searchItem.getItemTitle(),searchItem.getItemSellPoint(),searchItem.getItemPrice(),searchItem.getItemImage(),searchItem.getItemCategoryName(),searchItem.getItemDesc());
                //找高亮
                Map<String, HighlightField> highlightFields = hits[i].getHighlightFields();
                if (highlightFields!=null && highlightFields.size()>0){
                    //把高亮传进实体类里
                    searchItem2.setItem_title(highlightFields.get("itemTitle").
                            getFragments()[0].toString());

                }
                //添加到list集合里
                searchItemList2.add(searchItem2);
            }
            return searchItemList2;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public int insertDocument(String msg) throws IOException {
        // 1、根据商品id查询商品信息。
        SearchItem searchItem = searchItemMapper.getItemById(Long.valueOf(msg));
        //2、添加商品到索引库
        //创建添加请求对象
        IndexRequest indexRequest = new IndexRequest(ES_INDEX_NAME, ES_TYPE_NAME);
        //把数据通过json格式传进去
        indexRequest.source(JsonUtils.objectToJson(searchItem), XContentType.JSON);
        //请求响应
        IndexResponse indexResponse =
                restHighLevelClient.index(indexRequest,RequestOptions.DEFAULT);
        //返回结果
        return indexResponse.getShardInfo().getFailed();
    }

    @Override
    public int updateDocument(String msg) throws IOException {
        try {
        // 1、根据商品id查询商品信息。
        SearchItem searchItem = searchItemMapper.getItemById(Long.valueOf(msg));
        // 搜索请求对象
        SearchRequest searchRequest = new SearchRequest(ES_INDEX_NAME);
        searchRequest.types(ES_TYPE_NAME);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchQuery("id",msg));

                // 设置搜索源
                searchRequest.source(searchSourceBuilder);
        // 执行搜索
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits searchHits = search.getHits();
        SearchHit[] hits = searchHits.getHits();
        for (int i = 0; i < hits.length; i++) {
            SearchHit hit = hits[i];
            String id = hit.getId();
            UpdateRequest updateRequest = new UpdateRequest(ES_INDEX_NAME, ES_TYPE_NAME, id);
            updateRequest.doc(JsonUtils.objectToJson(searchItem), XContentType.JSON);
            UpdateResponse updateResponse =
                    restHighLevelClient.update(updateRequest,RequestOptions.DEFAULT);

        }
        return 0;
      } catch (IOException e) {
        e.printStackTrace();
            return 1;
        }

    }

    @Override
    public int deleteDocument(String msg) {
        try {
            // 1、根据商品id查询商品信息。
            SearchItem searchItem = searchItemMapper.getItemById(Long.valueOf(msg));
            // 搜索请求对象
            SearchRequest searchRequest = new SearchRequest(ES_INDEX_NAME);
            searchRequest.types(ES_TYPE_NAME);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.matchQuery("id",msg));

            // 设置搜索源
            searchRequest.source(searchSourceBuilder);
            // 执行搜索
            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits searchHits = search.getHits();
            SearchHit[] hits = searchHits.getHits();
            for (int i = 0; i < hits.length; i++) {
                SearchHit hit = hits[i];
                String id = hit.getId();
                //删除索引请求对象
                DeleteRequest deleteRequest = new DeleteRequest(ES_INDEX_NAME, ES_TYPE_NAME, id);
                //响应对象
                DeleteResponse deleteResponse =
                        restHighLevelClient.delete(deleteRequest,RequestOptions.DEFAULT);
            }
            return 0;
        } catch (IOException e) {
            e.printStackTrace();
            return 1;
        }

    }

    //判断索引是否存在
    private boolean isExistsIndex() throws IOException {
        GetIndexRequest getIndexRequest = new GetIndexRequest();
        getIndexRequest.indices(ES_INDEX_NAME);
        //把索引名通过GetIndexRequest对象传进去判断是否有
        return restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
    }
    //创建索引库
    private boolean createIndex() throws IOException {
        //创建索引请求对象，并设置索引名称
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(ES_INDEX_NAME);
        //设置索引参数使用map方式
        createIndexRequest.settings(Settings.builder().put("number_of_shards",2)
                .put("number_of_replicas",1));
        //使用json方式
        /*createIndexRequest.settings("{\n" +
                "    \"number_of_shards\": 2,\n" +
                "    \"number_of_replicas\": 1\n" +
                "  }", XContentType.JSON);*/
        createIndexRequest.mapping(ES_TYPE_NAME,"{\n" +
                "  \"_source\": {\n" +
                "    \"excludes\": [\n" +
                "      \"itemDesc\",\n" +
                "      \"item_desc\"\n" +
                "    ]\n" +
                "  },\n" +
                "  \"properties\": {\n" +
                "    \"itemTitle\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"analyzer\": \"ik_max_word\",\n" +
                "      \"search_analyzer\": \"ik_smart\"\n" +
                "    },\n" +
                "    \"itemSellPoint\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"analyzer\": \"ik_max_word\",\n" +
                "      \"search_analyzer\": \"ik_smart\"\n" +
                "    },\n" +
                "    \"itemPrice\": {\n" +
                "      \"type\": \"float\"\n" +
                "    },\n" +
                "    \"itemImage\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"index\": false\n" +
                "    },\n" +
                "    \"itemCategoryName\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"analyzer\": \"ik_max_word\",\n" +
                "      \"search_analyzer\": \"ik_smart\"\n" +
                "    },\n" +
                "    \"itemDesc\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"analyzer\": \"ik_max_word\",\n" +
                "      \"search_analyzer\": \"ik_smart\"\n" +
                "    }\n" +
                "  }\n" +
                "}",XContentType.JSON);
        //创建索引客户端
        IndicesClient indices = restHighLevelClient.indices();
        //创建响应对象
        CreateIndexResponse createIndexResponse = indices.create(createIndexRequest, RequestOptions.DEFAULT);
        //得到响应结果
        return createIndexResponse.isAcknowledged();
    }
}
